TYPE
DriveParameter: STRUCT
                  iIndex              : INT;        // Parameterindex 
                  iSubIndex           : INT;        // Parametersubindex
                  iScalingFactor      : INT   := 1; // Scaling factor from attributlist
                  iDataType           : INT;        // 2=Int8, 3=Int16, 4=Int32, 5=Unsigned8, 6=Unsigned16, 7=Unsigned32,  65=Byte, 66=Word, 67=DWord
                  xReadWrite          : BOOL;       // 0=Read Parameter, 1=Write Parameter  
                  xEnablePara         : BOOL;       // 0=Parameter ignored, 1=Parameter would be writen or read  
                  rWriteData          : REAL;       // Parametervalue in case of writing a drive parameter
                  dwReadData          : DWORD;      // Parametervalue as DWORD If a error xError=True dwData = Errorcode
                  diReadData          : DINT;       // Parametervalue as DINT
                  rReadData           : REAL;       // Parametervalue as REAL
                END_STRUCT;  
END_TYPE



FUNCTION_BLOCK DCO_R_W_n_DrivePar
TITLE = 'DCO_R_W_n_DrivePar'

// This FB read a List parameters of a connected drive
// The implementation is independant of the used Bussystem
// 
// Versionshistory:
// 1.0 Ersterstellung E.Dittmann
// 1.1 Bugfix ED
// 2.0 Release

// USED Lenze Funktionblocks
// FB300 DCO_ReadDriveParameter LIB: DCO
// FB301 DCO_WriteDriveParameter LIB: DCO
//  
// USED S7 Systemfuctions:
// SFB52 RDREC LIB: DP
// SFB53 WRREC LIB: DP
// SFB4  TON LIB: IEC_TC

VERSION : '2.0'
AUTHOR  : 'Lenze'
FAMILY  : 'DCO'
NAME : 'R_WnPara' // ( 8 Zeichen max.)
KNOW_HOW_PROTECT

CONST
    Range := 32; // Anzahl der Parameter die maximal zum Regler übertragen / gelesen werden 
END_CONST

VAR_INPUT
    iDiagnosticADR      : INT   := 2040;             // Diagnostic adress of the drive (Hardwareconfig S7)
    xExecute            : BOOL  := FALSE;            
    xUseIndexAsParam    : BOOL  := True;            // True = Lenze index number at wIndex
    iNumberOfParameter  : INT   := 1;               // Number of parameters 
END_VAR

VAR_IN_Out
    aDriveParameter     : ARRAY [1..Range] OF DriveParameter;
END_Var


VAR_OUTPUT
    xDone               :BOOL   := False;
    xBusy               :BOOL   := False;
    xTimeout            :BOOL   := False;
    xError              :BOOL   := False;
    dwErrorcode         :DWORD  := 0; 
    iErrorDataset       :INT    := 0;           // Index wich causes the Error
    iCounter            :INT    := 0;
END_VAR

VAR
    dwtest1             :DWORD;
    dwtest2             :DWORD;                    
    dwtest3             :DWORD; 
    iCount1             :INT:=1; 
    iCount2             :INT:=1;
    WritePara           :DCO_WriteDriveParameter;
    ReadPara            :DCO_ReadDriveParameter;
    xExecute_Old        :BOOL;
    xExecRW             :BOOL;
    xExecRW_Old         :BOOL;
    delay               :TON;
END_VAR

LABEL
    ENDE;
END_LABEL

// Initialisierung der Variablen
IF (xExecute = true) AND (xExecute_Old = False) THEN
    dwtest1:=0;
    dwtest2:=0;
    dwtest3:=0;
    xExecute_Old := True;
    dwErrorcode:=0;
    xDone:=False;
    xBusy:=False;
    xError:=False;
    iErrorDataset:=0;
    iCount1:=1;
    iCount2:=1;
    xExecRW:=True;
    xExecRW_OLD:=False;
    IF iNumberOfParameter > Range THEN
        iNumberOfParameter:=Range;
    END_IF;
    IF WritePara.xExecute THEN
        WritePara(iDiagnosticADR := iDiagnosticADR // IN: INT
                       ,xExecute := False// IN: BOOL
                         ,iIndex := aDriveParameter[1].iIndex // IN: INT
                      ,iSubIndex := aDriveParameter[1].iSubIndex // IN: INT
                          ,iType := aDriveParameter[1].iDataType // IN: INT
               ,xUseIndexAsParam := xUseIndexAsParam // IN: BOOL
                 ,iScalingFactor := aDriveParameter[1].iScalingFactor // IN: INT
                         ,rValue := aDriveParameter[1].rWriteData // IN: REAL
                                 ); 
    END_IF;
    IF ReadPara.xExecute THEN
        ReadPara(iDiagnosticADR := iDiagnosticADR // IN: INT
                      ,xExecute := False // IN: BOOL
                        ,iIndex := aDriveParameter[1].iIndex // IN: INT
                     ,iSubIndex := aDriveParameter[1].iSubIndex // IN: INT
              ,xUseIndexAsParam := xUseIndexAsParam // IN: BOOL
                ,iScalingFactor := aDriveParameter[1].iScalingFactor // IN: INT
                                ); 
    END_IF;
    GOTO ENDE;
END_IF;

// Timeout
delay(IN := xExecute  AND NOT xDone        // IN: BOOL
          ,PT := T#10s                           // IN: TIME
          ); 


IF NOT xExecute AND NOT xExecRW THEN // Reset ohne laufenden Auftrag
    GOTO ENDE;
ELSIF NOT xExecute AND xExecRW THEN // Reset mit laufendem Auftrag
    xExecRW:=False;   
END_IF;



    
IF (iCount2 <= iNumberOfParameter)  AND (iCount2 >= 1)THEN
    IF  aDriveParameter[iCount2].xReadWrite AND aDriveParameter[iCount2].xEnablePara THEN
        // Schreiben
        IF WritePara.xDone THEN
            xExecRW:=False;
        END_IF;

        WritePara(iDiagnosticADR := iDiagnosticADR // IN: INT
                       ,xExecute := xExecRW// IN: BOOL
                         ,iIndex := aDriveParameter[iCount2].iIndex // IN: INT
                      ,iSubIndex := aDriveParameter[iCount2].iSubIndex // IN: INT
                          ,iType := aDriveParameter[iCount2].iDataType // IN: INT
               ,xUseIndexAsParam := xUseIndexAsParam // IN: BOOL
                 ,iScalingFactor := aDriveParameter[iCount2].iScalingFactor // IN: INT
                         ,rValue := aDriveParameter[iCount2].rWriteData // IN: REAL
                                 ); 
        IF WritePara.xError THEN
            dwErrorCode:=SHL(IN:=WORD_TO_DWORD(WritePara.wErrorCode),N:=16) OR WORD_TO_DWORD(WritePara.wErrorInfo); 
            iErrorDataset := iCount2;
            iCount2:=iNumberOfParameter;
            xExecRW:=False;
            xError:=True;
        END_IF;
        IF (NOT WritePara.xDone AND NOT xExecRW AND NOT WritePara.xError AND xExecute) THEN
            iCount2:=Icount2 + 1;
            xExecRW:=True;
        END_IF; 
    ELSIF NOT aDriveParameter[iCount2].xReadWrite AND aDriveParameter[iCount2].xEnablePara THEN
 
       
        // Lesen
        
        IF ReadPara.xDone THEN
            xExecRW:=False;
        END_IF;
        
        ReadPara(iDiagnosticADR := iDiagnosticADR // IN: INT
                      ,xExecute := xExecRW // IN: BOOL
                        ,iIndex := aDriveParameter[iCount2].iIndex // IN: INT
                     ,iSubIndex := aDriveParameter[iCount2].iSubIndex // IN: INT
              ,xUseIndexAsParam := xUseIndexAsParam // IN: BOOL
                ,iScalingFactor := aDriveParameter[iCount2].iScalingFactor // IN: INT
                                ); 
           aDriveParameter[iCount2].dwReadData:= ReadPara.dwData; // OUT: DWORD
           aDriveParameter[iCount2].iDataType:= ReadPara.iDataType; // OUT: INT
           aDriveParameter[iCount2].rReadData:= ReadPara.rData; // OUT: REAL
           aDriveParameter[iCount2].diReadData:= ReadPara.diData; // OUT: DINT
        IF ReadPara.xError THEN
            dwErrorCode := ReadPara.dwData;
            iErrorDataset := iCount2 ;
            iCount2:=iNumberOfParameter;
            xExecRW:=False;
            xError:=True;
        END_IF;
        IF NOT ReadPara.xDone AND NOT xExecRW AND NOT ReadPara.xError AND xExecute THEN
            iCount2:=Icount2 + 1;
            xExecRW:=True;
        END_IF;
      
    ELSE
        // Weder lesen noch schreiben, Parameter wird ignoriert
        iCount2:=Icount2 + 1;
    END_IF;
         
    xBusy:= WritePara.xBusy OR  ReadPara.xBusy;
    //xError:= delay.q;
    xTimeout:= delay.q;
    iCounter:= iCount2;
    
    IF (iCount2 = (iNumberOfParameter + 1)) AND NOT xError THEN
        xDone:= True;
    ELSE
        xDone:= False;
    END_IF;
    
    
END_IF;

ENDE: 
IF NOT xExecute THEN
   xExecute_Old:=False;
   xError:=False;
   xBusy:=False;  
   xDone:=False;
   xExecRW:= False;
 //  iCount2:= 0;
END_IF;


END_FUNCTION_BLOCK
